package com.lly.markdown

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle

sealed class Element
class TextElement(var text: AnnotatedString) : Element()
data object Null : Element()
class ImageElement(val alt: String, val link: String) : Element()
sealed class Block {
     fun toPlaint(): String {
        return when (this) {
            is Decorater -> {
                when (decorater) {
                    Decorater.Bold -> {
                        "**${content}**"
                    }

                    Decorater.Italic -> {
                        "*${content}*"
                    }

                    Decorater.Underscore -> {
                        "__${content}__"
                    }

                    Decorater.DeleteLine -> {
                        "~~${content}~~"
                    }

                    else -> {
                        throw Exception("Block.toString():$content $decorater")
                    }
                }
            }

            is Image -> {
                "![${alt}](${link})"
            }

            Line -> "\n"
            is Link -> "[${doc}](${link})"
            is Plaint -> text
        }
    }

    fun toElement(): Element {
        val block = this
        val ans =
            when (block) {
                is Line -> {
                    TextElement(buildAnnotatedString { append("\n") })
                }

                is Decorater -> {

                    TextElement(buildAnnotatedString {
                        when (block.decorater) {
                            Decorater.Bold -> {
                                withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
                                    append(reduceText(block.content))
                                }
                            }

                            Decorater.Italic -> {
                                withStyle(SpanStyle(fontStyle = FontStyle.Italic)) {
                                    append(reduceText(block.content))
                                }
                            }

                            Decorater.Underscore -> {
                                withStyle(SpanStyle(textDecoration = TextDecoration.Underline)) {
                                    append(reduceText(block.content))
                                }
                            }

                            Decorater.DeleteLine -> {
                                withStyle(SpanStyle(textDecoration = TextDecoration.LineThrough)) {
                                    append(reduceText(block.content))
                                }
                            }
                        }

                    })
                }


                is Link -> {
                    TextElement(buildAnnotatedString {
                        pushStringAnnotation(
                            tag = LINK_TAG, annotation = block.link
                        )
                        withStyle(
                            style = SpanStyle(
                                color = Color.Blue, fontWeight = FontWeight.Bold
                            )
                        ) {
                            append(block.doc)
                        }
                        pop()
                    })
                }

                is Plaint -> TextElement(buildAnnotatedString { append(block.text) })

                is Image -> ImageElement(block.alt, block.link)
            }
        return ans
    }

    private fun reduceText(content: List<Block>): AnnotatedString {
        return content.toElements().filterIsInstance<TextElement>()
            .fold(AnnotatedString.Builder()) { acc, element ->
                acc.append(element.text)
                acc
            }.toAnnotatedString()
    }

    companion object {
        const val LINK_TAG = "URL"
    }
}

data class Link(val doc: String, val link: String) : Block()
data class Image(val alt: String, val link: String) : Block()
data class Plaint(val text: String) : Block()
data class Decorater(val content: List<Block>, val decorater: Int) : Block() {
    companion object {
        const val Bold = 0
        const val Italic = 1
        const val Underscore = 2
        const val DeleteLine = 3
    }
}

data object Line : Block()

fun List<Block>.toElements(): List<Element> {
    return map { it.toElement() }.fold(mutableListOf<Element>()) { list, e ->
        when (e) {
            is ImageElement -> list.add(e)
            Null -> {}
            is TextElement -> {
                if (list.isNotEmpty() && list.last() is TextElement) {
                    val last = list.last() as TextElement
                    last.text = buildAnnotatedString {
                        append(last.text)
                        append(e.text)
                    }
                } else {
                    list.add(e)
                }
            }
        }
        list
    }
}